import {Button, Divider, Popover, Segmented} from 'antd';
import React, {Dispatch, RefObject} from 'react';
import G6, {Graph, ICombo, IEdge, Edge, IGraph, INode, Node, ModelConfig} from '@antv/g6';
import registerBehavior from './register-behavior/index';
import registerNode from './register-node/index';
import registerEdge from './register-edge/index';
import bindEvent from './bind-event/index';

import './designer.scss';
import ModeType from './consts/mode-type';
import NodeType from './consts/node-type';
import GraphEventName from './consts/graph-event-name';
import NodeStateType from './consts/node-state-type';
import GraphKeyName from './consts/graph-key-name';
import {Item} from '@antv/g6-core/lib/types';
import StateType from './consts/state-type';
import G6Util from "./utils/g6-util";

declare var window: any;

interface IFlowDefDesignerProps {

}
interface IFlowDefDesignerState {
    graph: Graph | null;
    selectedNode: INode | null;
    selectedEdge: IEdge | null;
    clipboard: INode[] | null;
    mode: 'drag' | 'edit';
}

registerBehavior();
registerNode();
registerEdge();

const image = new Image();
image.src = ``;

class Designer extends React.Component<IFlowDefDesignerProps, IFlowDefDesignerState> {

    toolbarRef: RefObject<HTMLDivElement> = React.createRef();
    itembarRef: RefObject<HTMLDivElement> = React.createRef();
    propertyRef: RefObject<HTMLDivElement> = React.createRef();

    constructor(props: IFlowDefDesignerProps | Readonly<IFlowDefDesignerProps>) {
        super(props);
        this.state = {
            graph: null,
            selectedNode: null,
            selectedEdge: null,
            clipboard: null,
            mode: 'edit'
        };
    }

    componentDidMount() {
        console.log('componentDidMount');

        if (this.state.graph) {
            return ;
        }

        const toolbar = new G6.ToolBar({
            className: 'g6-component-toolbar tool-bar',
            position: {x: 20, y: 10},
            getContent: () => this.toolbarRef.current as HTMLDivElement
        });
        const itembar = new G6.ToolBar({
            className: 'g6-component-toolbar item-bar',
            position: {x: 20, y: 70},
            getContent: () => this.itembarRef.current as HTMLDivElement
        });
        const propertybar = new G6.ToolBar({
            className: 'g6-component-toolbar property-bar',
            position: {x: window.innerWidth - 220 - 10, y: 10},
            getContent: () => this.propertyRef.current as HTMLDivElement
        });

        const graph = new G6.Graph({
            container: 'flow-canvas-wrap',
            width: window.innerWidth,
            height: window.innerHeight - 10,
            groupByTypes: false,
            plugins: [toolbar, itembar, propertybar], // 配置 ToolBar 插件
            animate: true,
            // renderer: 'svg',
            modes: {
                default: ['drag-node', 'click-select'],
                addNode: ['click-node-add', 'click-select'],
                addEdge: ['click-add-edge', 'click-select'],
                edit: [
                    'custom:node:drop',
                    'custom:anchor:hover',
                    'custom:ghost-node:display',
                    'custom:ghost-edge:display',
                    'custom:items:set-select',
                    'drag-node', /*'click-select'*/
                ],
                select: [
                    'click-select', 'brush-select'
                ],
                drag: [
                    'drag-canvas'
                ]
            },
            nodeStateStyles: {
                // 鼠标 hover 上节点，即 hover 状态为 true 时的样式
                hover: {
                    fill: 'lightsteelblue',
                },
                // 鼠标点击节点，即 click 状态为 true 时的样式
                click: {
                    stroke: '#000',
                    lineWidth: 3,
                },
            },
            edgeStateStyles: {
                ghost: {
                    lineDash: [2, 1]
                }
            },
            defaultEdge: {
                style: {
                    stroke: '#aeaeae',
                    lineWidth: 1.5,
                    endArrow: {
                        path: 'M 0,0 L 9,3 L 9,-3 Z',
                        fill: '#aeaeae',
                    },
                }
            }
        });
        this.setState({graph});

        graph.setMode(this.state.mode);
        graph.setTextWaterMarker(['一二三四五六七八九十', 'ABCDEFG', '1234567890', '😄😳🙂😁']);

        bindEvent(graph);

        graph.on(GraphEventName.ITEM_SELECTED, (item: INode | IEdge) => {
            if (item instanceof Node) {
                this.setState({selectedNode: item, selectedEdge: null});
            } else if (item instanceof Edge) {
                this.setState({selectedNode: null, selectedEdge: item});
            }
            item.setState(StateType.SELECTED, true);
        });
        graph.on(GraphEventName.ITEM_CLEAR_SELECTED, (node: INode) => {
            this.setState({selectedNode: null});
            node?.setState(StateType.SELECTED, false);
        });
        // graph.on(GraphEventName.NODES_ANCHOR_BOLD, (exceptNode: INode) => {
        //     graph.getNodes().filter((node: INode) => node !== exceptNode).forEach((node: INode) => {
        //         node.getContainer().getChildren().forEach(child => {
        //             if (child.attr(NodeAttrField.ANCHOR_IS_ANCHOR)) {
        //                 child.attr(anchorStyle.boldStyle);
        //             }
        //         });
        //     });
        // });
        // graph.on(GraphEventName.NODES_ANCHOR_BOLD_FOCUS, (node: INode) => {
        //     graph.getNodes().filter((node: INode) => node !== exceptNode).forEach((node: INode) => {
        //         node.getContainer().getChildren().forEach(child => {
        //             if (child.attr(NodeAttrField.ANCHOR_IS_ANCHOR)) {
        //                 child.attr({
        //                     fill: '#e1f5fe',
        //                     stroke: '#81d4fa',
        //                     lineWidth: 4,
        //                     r: 8,
        //                     opacity: .9,
        //                 });
        //             }
        //         });
        //     });
        // });
        // graph.on(GraphEventName.NODES_ANCHOR_THIN, () => {
        //     graph.getNodes().forEach((node: INode) => {
        //         node.getContainer().getChildren().forEach(child => {
        //             if (child.attr(NodeAttrField.ANCHOR_IS_ANCHOR)) {
        //                 child.attr(anchorStyle.thinStyle);
        //             }
        //         });
        //     });
        // });

        window.graph = graph;
    }

    handleNodeItemDragstart(event: React.DragEvent<HTMLImageElement>) {
        event.dataTransfer.setDragImage(image, 1, 1);
        const nodeType = (event.target as HTMLElement).getAttribute('node-type');
        this.state.graph?.set(GraphKeyName.MODE, ModeType.NODE_ADD);

        const selectedNodes = this.state.graph?.findAllByState('node', 'selected');
        const selectedEdges = this.state.graph?.findAllByState('edge', 'selected');

        this.state.graph?.emit(GraphEventName.ITEMS_CLEAR_SELECT, selectedNodes, false);
        this.state.graph?.emit(GraphEventName.ITEMS_CLEAR_SELECT, selectedEdges, false);

        if (nodeType === NodeType.START_EVENT) {
            const currentStart = this.state.graph?.find('node', node => node.getModel().type === 'start-event');
            if (currentStart) {
                event.preventDefault();
            }
        }
    }

    handleNodeItemDrag(event: React.DragEvent<HTMLImageElement>) {
        this.state.graph?.emit(GraphEventName.GHOST_NODE_DISPLAY, event);
    }

    handleNodeItemDragend(event: React.DragEvent<HTMLImageElement>) {
        this.state.graph?.emit(GraphEventName.NODE_DROP, event);
        this.state.graph?.set(GraphKeyName.MODE, '');
        // this.state.graph?.set('$nodeType', null);
    }

    handleModeChange(mode: 'edit' | 'drag') {
        this.setState({mode, selectedEdge: null, selectedNode: null});
        this.state.graph?.setMode(mode);
        this.state.graph?.emit(GraphEventName.ITEMS_CLEAR_SELECT);
        this.state.graph?.getNodes().forEach(node => node.setState(NodeStateType.NODE_SELECTED, false));
        this.state.graph?.getEdges().forEach(edge => edge.setState(NodeStateType.NODE_SELECTED, false));
    }

    save(event: React.MouseEvent) {
        console.log(this.state.graph?.save());
    }

    copy(event: React.MouseEvent) {
        const selectedNodes = this.state.graph?.findAll('node', (node: INode) => node.getModel().type !== NodeType.START_EVENT && node.hasState(StateType.SELECTED)) || [];
        this.setState({clipboard: selectedNodes});
    }

    paste(event: React.MouseEvent) {
        const selectedNodes = this.state.clipboard || [];
        selectedNodes.forEach((selectedNode: INode) => {
            const {clazz, x, y, type, label} = selectedNode.getModel();
            const model = {
                clazz,
                x: x as number + 50,
                y: y as number + 50,
                id: G6Util.generateNodeId(type as string, 6),
                type,
                label: `${label} （复制）`
            } as ModelConfig;

            const item = this.state.graph?.addItem('node', model, true) as Item;
        });
        this.setState({clipboard: null});
    }

    delete(event: React.MouseEvent) {
        const selectedNodes = this.state.graph?.findAll('node', (node: INode) => node.getModel().type !== NodeType.START_EVENT && node.hasState(StateType.SELECTED)) || [];
        selectedNodes.forEach((selectedNode: INode) => {
            this.state.graph?.removeItem(selectedNode, true);
        });
        this.setState({
            selectedNode: null,
            selectedEdge: null,
        });
    }

    zoom(ratio: number = 2) {
        this.state.graph?.zoom(ratio, undefined, true, {
            duration: 100,
        });
    }

    zoomTo(ratio: number = 1) {
        this.state.graph?.zoomTo(ratio, undefined, true, {
            duration: 100,
        });
    }

    propertyWrap() {
        const {selectedNode, selectedEdge} = this.state;
        if (selectedNode) {
            return <div>当前选择节点：{selectedNode?.getModel().id}</div>;
        } else if (selectedEdge) {
            return <div>当前选择连接线：{selectedEdge?.getModel().id}</div>;
        }
        return <div>流程属性</div>;
    }

    render() {
        return (
            <div className='flow-def--designer-wrap'>
                <div style={{display: 'none'}}>
                    <div ref={this.toolbarRef}>
                        <Popover placement='top' content='保存'>
                            <Button type='text'><i className='spb-lern spb-lern-save' onClick={(event: React.MouseEvent) => this.save(event)}/></Button>
                        </Popover>
                        {/*<Divider type='vertical' />*/}
                        {/*<Popover placement='top' content='撤销'>*/}
                        {/*    <Button type='text'><i className='spb-lern spb-lern-undo' onClick={(event: React.MouseEvent) => this.undo()}/></Button>*/}
                        {/*</Popover>*/}
                        {/*<Popover placement='top' content='重做'>*/}
                        {/*    <Button type='text'><i className='spb-lern spb-lern-redo' onClick={(event: React.MouseEvent) => this.redo()}/></Button>*/}
                        {/*</Popover>*/}
                        <Divider type='vertical' />
                        <Popover placement='top' content='复制'>
                            <Button type='text' onClick={(event: React.MouseEvent) => this.copy(event)}><i className='spb-lern spb-lern-copy'/></Button>
                        </Popover>
                        <Popover placement='top' content='粘贴'>
                            <Button type='text' onClick={(event: React.MouseEvent) => this.paste(event)}><i className='spb-lern spb-lern-paste'/></Button>
                        </Popover>
                        <Popover placement='top' content='删除'>
                            <Button type='text' onClick={(event: React.MouseEvent) => this.delete(event)}><i className='spb-lern spb-lern-delete'/></Button>
                        </Popover>
                        <Divider type='vertical' />
                        <Popover placement='top' content='缩小'>
                            <Button type='text' onClick={(event: React.MouseEvent) => this.zoom(0.8)}><i className='spb-lern spb-lern-zoom-in'/></Button>
                        </Popover>
                        <Popover placement='top' content='放大'>
                            <Button type='text' onClick={(event: React.MouseEvent) => this.zoom(1.2)}><i className='spb-lern spb-lern-zoom-out'/></Button>
                        </Popover>
                        <Popover placement='top' content='原始大小'>
                            <Button type='text' onClick={(event: React.MouseEvent) => this.zoomTo(1)}><i className='spb-lern spb-lern-ratio_1'/></Button>
                        </Popover>
                        <Divider type='vertical' />

                        <Segmented
                            size='small'
                            value={this.state.mode}
                            onChange={(event) => this.handleModeChange(event as 'drag' | 'edit')}
                            options={[
                                {
                                    label: '编辑模式',
                                    value: 'edit',
                                    icon: (
                                            <i className='spb-lern spb-lern-edit'/>
                                    ),
                                },
                                {
                                    label: '拖动画布',
                                    value: 'drag',
                                    icon: (
                                            <i className='spb-lern spb-lern-drag'/>
                                    ),
                                },
                            ]}
                        />
                        &nbsp;
                    </div>
                    <div ref={this.itembarRef}>
                        <div className='node-title'>
                            节点
                        </div>
                        <div className='node-wrap'>
                            {/*<Popover placement='right' content='开始节点'>*/}
                            <img alt='开始节点' node-type='start-event' src={require('@/assets/node/start.svg').default} draggable={true}
                                 onDragStart={(event) => this.handleNodeItemDragstart(event)}
                                 onDrag={(event) => this.handleNodeItemDrag(event)}
                                 onDragEnd={(event) => this.handleNodeItemDragend(event)}
                            />
                            <div className='node-desc'>开始节点</div>
                            {/*</Popover>*/}
                        </div>
                        <div className='node-wrap'>
                            {/*<Popover placement='right' content='用户节点'>*/}
                            <img alt='用户节点' node-type='user-task' src={require('@/assets/node/user-task.svg').default}
                                 onDragStart={(event) => this.handleNodeItemDragstart(event)}
                                 onDrag={(event) => this.handleNodeItemDrag(event)}
                                 onDragEnd={(event) => this.handleNodeItemDragend(event)}
                            />
                            <div className='node-desc'>用户节点</div>
                            {/*</Popover>*/}
                        </div>
                        <div className='node-wrap'>
                            {/*<Popover placement='right' content='分支节点'>*/}
                            <img alt='分支节点' node-type='exclusive-gateway' src={require('@/assets/node/exclusive-gateway.svg').default}
                                 onDragStart={(event) => this.handleNodeItemDragstart(event)}
                                 onDrag={(event) => this.handleNodeItemDrag(event)}
                                 onDragEnd={(event) => this.handleNodeItemDragend(event)}
                            />
                            <div className='node-desc'>分支节点</div>
                            {/*</Popover>*/}
                        </div>
                        <div className='node-wrap'>
                            {/*<Popover placement='right' content='结束节点'>*/}
                            <img alt='结束节点' node-type='end-event' src={require('@/assets/node/end.svg').default}
                                 onDragStart={(event) => this.handleNodeItemDragstart(event)}
                                 onDrag={(event) => this.handleNodeItemDrag(event)}
                                 onDragEnd={(event) => this.handleNodeItemDragend(event)}
                            />
                            <div className='node-desc'>结束节点</div>
                            {/*</Popover>*/}
                        </div>
                    </div>
                    <div ref={this.propertyRef}>
                        属性栏
                        {
                            this.propertyWrap()
                        }
                    </div>
                </div>
                <div id='flow-canvas-wrap'>
                </div>
            </div>
        );
    }

}


export default Designer;
